import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;

public class CipherTextAttack {
	//oidhjdfol
	//fsdfsdf
	//lskdgjlksdj
	//dcfghdf
	private char[][] m_keyArray = new char[8][2];
	private int m_sizeOfInitialVector;
	private byte[][] m_blocks;
	private int m_tens;
	private byte[] m_initialVector;
	private byte[] m_encrypted;
	private byte[][][] m_decrypted;


	public CipherTextAttack(byte[] text, byte[] initialVector,int initialVectorSize)
			throws IOException {
		m_sizeOfInitialVector = initialVectorSize;
		m_tens = 0;
		if (text.length % 10 != 0)
			m_tens = 1;
		m_blocks = new byte[text.length / 10 + m_tens][10];// create room for
															// the text by blocks
		m_initialVector = initialVector;
		MoveToBlocks(text);// move to block of ten
		int i;
		for (i = 0; i < 8; i++) {// puts in the array
			m_keyArray[i][0] = (char) (((int) 'a') + i);
		}
	}

	public void Encrypt(String key,File first) throws IOException {
		EncryptionKey(key);// generate a key
		int i, j;
		m_encrypted = new byte[10];
		String path=first.getName();
		path=path.substring(0,path.length()-4);
		for(i=0;i<m_sizeOfInitialVector;i++)
			m_encrypted[i] = m_initialVector[i];
		for (i = 0; i < m_blocks.length; i++) {
			for (j = 0; j < m_blocks[i].length; j++) {
				m_encrypted[j] = (byte) (m_blocks[i][j] ^ m_encrypted[j]);
				// does the Xor between the initial vector and the text
				if(m_encrypted[j]>'a'-1 && m_encrypted[j] < 'h' + 1)
					ChangeToEncryptedKey(j);
			}
			
			FileWriter file = new FileWriter(path+".cipher", true);
			file.write(new String(m_encrypted));
			file.close();
		}
	}
	
	private void ChangeToEncryptedKey(int i){
			m_encrypted[i] = (byte) m_keyArray[ m_encrypted[i] - 'a'][1]; 
			}
	
	public void Decrypt() throws IOException{
		int i,j;
		m_encrypted = new byte[10];
		m_decrypted = new byte[m_blocks.length][10][2];
		for(i = 0; i < m_blocks.length; i++){
			for(j = 0; j < 10; j++){
				m_encrypted[j] = m_blocks[i][j];
			}
			for(j = 0; j < 10;j++){
				if(m_encrypted[j] >= 'a' && m_encrypted[j] <= 'h'){
					m_decrypted[i][j][1] = m_initialVector[j];
					m_decrypted[i][j][0] = m_encrypted[j];
				//	m_count[m_encrypted[j] - 'a']++;
				}else{
					m_decrypted[i][j][1] = -1;
					m_decrypted[i][j][0] =  (byte)(m_initialVector[j] ^ m_encrypted[j]);
				}
			}
			m_initialVector = m_blocks[i];
		}
		TryThis();
		
		return;
	}
	
	private void TryThis(){
		int i,j,k;

		int[][] key = new int[8][8];
			for(i = 0; i < m_decrypted.length;i++){
				for(j = 0; j < 10; j++){
					if(m_decrypted[i][j][0] >= 'a' && m_decrypted[i][j][0] <= 'h' && m_decrypted[i][j][1] != -1){
						for(k = 0; k < 8 ; k++){
							
								int temp=((byte)(k +'a') ^ m_decrypted[i][j][1]) ;
							if((temp > 31 && temp < 126)  )
							{
								key[m_decrypted[i][j][0] - 'a'][k]++;
							}
							else{
								if((temp>0 && temp < 32)&& !(temp ==10||temp==13||temp==9) )
									key[m_decrypted[i][j][0] - 'a'][k] = Integer.MIN_VALUE;
							}
							}
					}	
				}
			}
			int goal=0;
		for (i = 0; i < 8; i++){
			goal=0;
			for(j = 0; j < 8;j++){
				
				if(key[i][j] > goal){
					
					goal=key[i][j];
					
					m_keyArray[i][1]=(char)('a'+j);
					
				}
				
				
			}
			//System.out.println();
		}

		
	}

	private void EncryptionKey(String key) {
		int i;
		Boolean check=false;
		char pos=' ';
		for (i = 0; i <key.length(); i++) {
				if(key.charAt(i)==' ' || key.charAt(i)=='\n')
					continue;
				else
				{
					if(check==false)
					{
						pos=key.charAt(i);
						check =true;
					}
					else
					{
						check=false;
						m_keyArray[pos-'a'][1] =key.charAt(i);
					}
				}
		}
	}

	private void MoveToBlocks(byte[] text) {
		int i, j;
		for (i = 0; i < m_blocks.length; i++) {
			for (j = 0; j < 10; j++) {
				if (text.length > i * 10 + j)// check if length of the array is
												// bigger or it needs to put
												// zero
					m_blocks[i][j] = text[i * 10 + j];//puts the value inside of it
				else
					m_blocks[i][j] = 0;//if bigger puts zero
			}
		}
	}

		public char[] GetKey() {
		int i;
		char[] res = new char[8];
		for (i = 0; i < 8; i++)
			res[i] = m_keyArray[i][1];
		return res;
	}

	public static void main(String[] args) throws IOException {
		int i; 
		byte[] key;
		String start = args[0];
		
		if (start.equals("EncryptionA"))
		{
			File first = new File(args[1]);
			File second = new File(args[3]);
			File third =new File(args[2]);
			key=Files.readAllBytes(third.toPath());
			String Skey=new String(key);
			int initialVectorSize = 10;
			byte[] text = Files.readAllBytes(first.toPath());// reads the file to bytes
			byte[] initialVector = Files.readAllBytes(second.toPath());
			CipherTextAttack toEncrypt = new CipherTextAttack(text,initialVector,initialVectorSize);	
			toEncrypt.Encrypt(Skey,first);

			}
		if (start.equals("DecryptionA")){
			File first = new File(args[1]);
			File second = new File(args[2]);
			int initialVectorSize = 10;
			byte[] text = Files.readAllBytes(first.toPath());// reads the file to bytes
			byte[] initialVector = Files.readAllBytes(second.toPath());
			CipherTextAttack toEncrypt = new CipherTextAttack(text,initialVector,initialVectorSize);
				toEncrypt.Decrypt();
				char[] res = toEncrypt.GetKey();
				FileWriter writer = new FileWriter(first+"_Key.txt");
				for(i = 0; i < res.length;i++){
					char temp = 'a';
					temp = (char) (temp + i);
					writer.write(res[i]+ " " + temp+'\n');
				}
				writer.close(); 
			
		}		
		
		}

	public void PrintArray(char[][] array) {
		int i;
		for (i = 0; i < array.length; i++) {
			System.out.println(array[i][0]);
		}
	}
}
